#include <memory.h>
#include "vector.h"
#include "z_memory.h"
#include "z_logger.h"

vector_t *vector_new() {
    return (vector_t *) z_calloc(1, sizeof(vector_t));
}

void vector_free(vector_t *obj) {
    if (!obj) return;

    vector_clear(obj);
    z_free(obj);
}

void vector_clear(vector_t *obj) {
    if (!obj) return;

    obj->size = 0;
    z_free(obj->vals);
}

size_t vector_size(const vector_t *obj) {
    return obj ? obj->size : 0;
}

void *vector_get(const vector_t *obj, size_t idx) {
    if (obj && idx < obj->size) {
        return obj->vals[idx];
    } else {
        return NULL;
    }
}

void vector_set(vector_t *obj, size_t idx, void *val) {
    if (!obj) return;

    if (idx < obj->size) {
        obj->vals[idx] = val;
    } else {
        log_error("The indexes(%zu) exceed the range(0-%lu)", idx, obj->size - 1);
    }
}

int vector_add(vector_t *obj, void *val) {
    if (!obj) return -1;

    if (obj->size >= 0x1000) {
        log_error("To be add object more than the maximum capacity limit(%d)", 0x1000);
        return -1;
    }

    if (0 == obj->capi) {
        obj->size = 0;
        obj->capi = 0x10;
        obj->vals = (void **) z_calloc(obj->capi, sizeof(void *));
    } else if (obj->size >= obj->capi) {
        obj->capi <<= 2;
        void **buf = z_calloc(obj->capi, sizeof(void *));
        memmove(buf, obj->vals, obj->size * sizeof(void *));
        z_free(obj->vals);
        obj->vals = buf;
    }

    obj->vals[obj->size] = val;
    ++obj->size;

    return 0;
}

void vector_foreach(const vector_t *obj, vector_foreach_callback cb_function) {
    if (!obj) return;

    for (size_t i = 0; i < obj->size; ++i) {
        cb_function(obj->vals[i]);
    }
}

void vector_foreach_r(const vector_t *obj, vector_foreach_callback cb_function) {
    if (!obj) return;

    for (size_t i = obj->size - 1; i >= 0; --i) {
        cb_function(obj->vals[i]);
    }
}

void vector_foreach_free(const vector_t *obj) {
    vector_foreach(obj, vector_item_free);
}

void *vector_item_new(size_t size) {
    return z_calloc(1, size);
}

void vector_item_free(void *ptr) {
    z_free(ptr);
}
